/**
 * ***************************************************************
 * JADE - Java Agent DEvelopment Framework is a framework to develop multi-agent
 * systems in compliance with the FIPA specifications. Copyright (C) 2000 CSELT
 * S.p.A.
 *
 * GNU Lesser General Public License
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, version 2.1 of the License.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * **************************************************************
 */
package agentsystem;

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.TickerBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAException;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

/**
 * This example shows a minimal agent that just prints "Hallo World!" and then
 * terminates.
 *
 * @author Giovanni Caire - TILAB
 */
public class ConsumerAgent extends Agent {

    // The list of known producer agents
    private AID[] producerAgents;
    
    //taste of this customer
    private Product myTaste;
    static final int numberOfProductProperties=Product.numberOfProductProperties;

    protected void setup() {
       

         // Register the consumer in the yellow pages for market research
        DFAgentDescription dfd = new DFAgentDescription();
        dfd.setName(getAID());
        ServiceDescription sd = new ServiceDescription();
        sd.setType("coke-consumer");
        sd.setName("JADE-coke-consumer");
        dfd.addServices(sd);
        try {
            DFService.register(this, dfd);
        } catch (FIPAException fe) {
            fe.printStackTrace();
        }
        
        
        myTaste=Product.createRandom();

        this.addBehaviour(new ConsumeCoke(this, 900));
        this.addBehaviour(new ConsumerAgent.TasteInfoRequestServer());
        // Make this agent terminate
        // doDelete();
    }

    /**
     * Inner class ConsumeCoke. This is the behaviour used by Consumers
     * to consume a coke regularly
     */
    private class ConsumeCoke extends TickerBehaviour {

        public ConsumeCoke(Agent a, long period) {
            super(a, period);
        }

        @Override
        protected void onTick() {
            //System.out.println("Trying to buy coke");
            // Update the list of seller agents
            DFAgentDescription template = new DFAgentDescription();
            ServiceDescription sd = new ServiceDescription();
            sd.setType("coke-producer");
            template.addServices(sd);
            try {
                DFAgentDescription[] result = DFService.search(myAgent, template);
                //System.out.println("Found the following producer agents:");
                producerAgents = new AID[result.length];
                for (int i = 0; i < result.length; ++i) {
                    producerAgents[i] = result[i].getName();
                    //System.out.println(producerAgents[i].getName());
                }
            } catch (FIPAException fe) {
                fe.printStackTrace();
            }

            // Perform the request
            myAgent.addBehaviour(new ConsumerAgent.RequestPerformer());
        }
    }

    private class RequestPerformer extends Behaviour {

        private AID favouriteProducer;
        private double bestTasteDifference;
        private int repliesCnt = 0; // The counter of replies from seller agents
        private MessageTemplate mt; // The template to receive replies
        private int step = 0;

        public void action() {
            switch (step) {
                case 0:
                    // Send the cfp to all sellers
                    ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
                    for (int i = 0; i < producerAgents.length; ++i) {
                        cfp.addReceiver(producerAgents[i]);
                    }
                    cfp.setContent("What is your product?");
                    cfp.setConversationId("buying-coke");
                    cfp.setReplyWith("cfp" + System.currentTimeMillis()); // Unique value
                    myAgent.send(cfp);
                    // Prepare the template to get proposals
                    mt = MessageTemplate.and(MessageTemplate.MatchConversationId("buying-coke"),
                            MessageTemplate.MatchInReplyTo(cfp.getReplyWith()));
                    step = 1;
                    break;
                case 1:
                    // Receive all proposals/refusals from seller agents
                    ACLMessage reply = myAgent.receive(mt);
                    if (reply != null) {
                        // Reply received
                        if (reply.getPerformative() == ACLMessage.PROPOSE) {
                            Product product= new Product(reply.getContent());
                            double tasteDifference=myTaste.differenceTo(product);
                            if (favouriteProducer == null || tasteDifference < bestTasteDifference) {
                                // This is the best offer at present
                                bestTasteDifference = tasteDifference;
                                favouriteProducer = reply.getSender();
                            }
                        }
                        repliesCnt++;
                        if (repliesCnt >= producerAgents.length) {
                            // We received all replies
                            step = 2;
                        }
                    } else {
                        block();
                    }
                    break;
                case 2:
                    //System.out.println("buying coke: difference is "+bestTasteDifference);
                    // Send the purchase order to the seller that provided the best offer
                    ACLMessage order = new ACLMessage(ACLMessage.ACCEPT_PROPOSAL);
                    order.addReceiver(favouriteProducer);
                    order.setContent("I am buying your coke");
                    order.setConversationId("buying-coke");
                    order.setReplyWith("order" + System.currentTimeMillis());
                    myAgent.send(order);
                    // Prepare the template to get the purchase order reply
                    mt = MessageTemplate.and(MessageTemplate.MatchConversationId("buying-coke"),
                            MessageTemplate.MatchInReplyTo(order.getReplyWith()));
                    myTaste=Product.createRandom();
                    step = 3;
                    break;
                
            }
        }

        public boolean done() {
            if (step == 2 && favouriteProducer == null) {
                System.out.println("Attempt failed: no producers found");
            }
            return ((step == 2 && favouriteProducer == null) || step == 3);
        }
    }  // End of inner class RequestPerformer

    private class TasteInfoRequestServer extends CyclicBehaviour {

        @Override
        public void action() {
            MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.CFP);
            ACLMessage msg = myAgent.receive(mt);
            if (msg != null) {
                // CFP Message received. Reply with my product
                ACLMessage reply = msg.createReply();

                reply.setPerformative(ACLMessage.PROPOSE);
                reply.setContent(myTaste.toString());

                myAgent.send(reply);
            } else {
                block();
            }
        }
    }
    
    
    protected void takeDown() {
        //System.out.println(getLocalName()+" committing suicide");
    }
    
    
}
